/*
 * Bayes.cpp
 *
 *  Created on: 19-11-2011
 *      Author: cristian
 */

#include "Bayes.h"

Bayes::Bayes() {

	logger = new Logger();

	wordsmap = new std::map<unsigned int, map<string, unsigned int>*>;
	map<string, unsigned int>* palabrasNoSpam = new map<string, unsigned int>;
	map<string, unsigned int>* palabrasSpam = new map<string, unsigned int>;

	wordsmap->insert(pair<unsigned int, map<string, unsigned int>*>(SPAM, palabrasSpam));
	wordsmap->insert(pair<unsigned int, map<string, unsigned int>*>(NO_SPAM, palabrasNoSpam));

}

Bayes::~Bayes() {

	delete wordsmap;
	delete logger;
}

unsigned int Bayes::getWordCant(string *word, unsigned int categoria) {
	if (categoria == SPAM || categoria == NO_SPAM) {

		if (word != NULL) {

			map<unsigned int, map<string, unsigned int>*>::iterator iter = this->wordsmap->begin();

			iter = this->wordsmap->find(categoria);

			if (iter != this->wordsmap->end()) {

				map<string, unsigned int>* nodeword = iter->second;

				if (nodeword != NULL) {

					map<string, unsigned int>::iterator iterWord = nodeword->begin();

					iterWord = nodeword->find(word->c_str());

					if (iterWord != nodeword->end()) {
						return iterWord->second;
					} else {
						//	HAL_TRACE_CORE(logger, "palabra no encontrada ...");
						return 0;
					}
				} else {
					HAL_ERROR(logger, " Listado de palabras de la categoria es NULL...");
					return 0;
				}

			} else {
				HAL_ERROR(logger, " Categoria No encontrada ");
				return 0;
			}
		} else {
			HAL_ERROR(logger, " Palabra NULL ");
			return 0;
		}

	} else {
		HAL_ERROR(logger, " Categoria no es SPAM =%i o NO SPAM= %i  -> %i", SPAM, NO_SPAM, categoria);
		return 0;
	}
	return 0;
}

map<string, unsigned int> *Bayes::getWordMap(string *word, unsigned int categoria) {
	if (categoria == SPAM || categoria == NO_SPAM) {

		if (word != NULL) {

			map<unsigned int, map<string, unsigned int>*>::iterator iter = this->wordsmap->begin();

			iter = this->wordsmap->find(categoria);

			if (iter != this->wordsmap->end()) {

				map<string, unsigned int>* nodeword = iter->second;

				if (nodeword != NULL) {

					map<string, unsigned int>::iterator iterWord = nodeword->begin();

					iterWord = nodeword->find(word->c_str());

					if (iterWord != nodeword->end()) {

						map<string, unsigned int>* valor = new map<string, unsigned int>;
						valor->insert(pair<string, unsigned int>(word->c_str(), iterWord->second));
						return valor;
					} else {
						HAL_TRACE_CORE(logger, "palabra no encontrada ...");
					}
				} else {
					HAL_ERROR(logger, " Listado de palabras de la categoria es NULL...");
					return NULL;
				}

			} else {
				HAL_ERROR(logger, " Categoria No encontrada ");
				return NULL;
			}
		} else {
			HAL_ERROR(logger, " Palabra NULL ");
			return NULL;
		}

	} else {
		HAL_ERROR(logger, " Categoria no es SPAM =%i o NO SPAM= %i  -> %i", SPAM, NO_SPAM, categoria);
		return NULL;
	}
	return NULL;
}

void Bayes::putWordInCategory(unsigned int categoria, string *word, unsigned int count) {
	if (categoria == SPAM || categoria == NO_SPAM) {

		if (word != NULL) {

			map<unsigned int, map<string, unsigned int>*>::iterator iter = this->wordsmap->begin();

			iter = this->wordsmap->find(categoria);

			if (iter != this->wordsmap->end()) {

				map<string, unsigned int>* nodeword = iter->second;

				if (nodeword != NULL) {

					map<string, unsigned int>::iterator iterWord = nodeword->begin();

					iterWord = nodeword->find(word->c_str());

					if (iterWord != nodeword->end()) {
						iterWord->second++;
					} else {
						//string* wordclone = new string(word->c_str());
						nodeword->insert(std::pair<string, unsigned int>(word->c_str(), count));

					}
				} else {
					HAL_ERROR(logger, " Listado de palabras de la categoria es NULL...");
				}

			} else {
				HAL_ERROR(logger, " Categoria No encontrada ");
			}
		} else {
			HAL_ERROR(logger, " Palabra NULL ");
		}

	} else {
		HAL_ERROR(logger, " Categoria no es SPAM =%i o NO SPAM= %i  -> %i", SPAM, NO_SPAM, categoria);
	}
}

void Bayes::loadCSVFile(string *filepath) {
	if (filepath == NULL) {
		HAL_ERROR(logger, "filepath nulo");
	}

	std::ifstream data(filepath->c_str(), ifstream::in);
	std::string line;

	while (std::getline(data, line)) {

		std::stringstream lineStream(line);
		std::string cell;
		unsigned int col = 0;
		unsigned int categoria = 0;

		while (std::getline(lineStream, cell, ';')) {

			string buf;
			stringstream ss(cell);

			while (ss >> buf) {

				if (col == 0) {

					if (buf.compare("SPAM") == 0) {
						categoria = SPAM;
						col++;
						continue;
					}

					if (buf.compare("NOSPAM") == 0) {
						categoria = NO_SPAM;
						col++;
						continue;
					}

				}

				buf.erase(std::remove(buf.begin(), buf.end(), ' '), buf.end());
				std::transform(buf.begin(), buf.end(), buf.begin(), ::tolower);

				std::wstring ws(buf.length(), L' ');

				std::copy(buf.begin(), buf.end(), std::back_inserter(ws));
				StemSpanish(ws);

				if (ws.size() > LARGO_MINIMO) {

					string* word = new string();

					word->assign(ws.begin(), ws.end());

					if (categoria == SPAM) {
						this->putWordInCategory(SPAM, word, 1);
						this->putWordInCategory(NO_SPAM, word, 0);
					}

					if (categoria == NO_SPAM) {
						this->putWordInCategory(NO_SPAM, word, 1);
						this->putWordInCategory(SPAM, word, 0);
					}

				}
				col++;
			}
		}
	}

}

void Bayes::openfileAndTest(string *filepath) {

	if (filepath == NULL) {
		HAL_ERROR(logger, "filepath nulo");
	}

	std::ifstream data(filepath->c_str(), ifstream::in);
	std::string line;


	unsigned int catSPAMCorrectos = 0;
	unsigned int catSPAMIncorrectos = 0;

	unsigned int catNOSPAMcorrectos = 0;
	unsigned int catNOSPAMIncorrectos = 0;


//	unsigned int catDuda = 0;
	int linea = 1;

	while (std::getline(data, line)) {

		std::stringstream lineStream(line);
		std::string cell;
		unsigned int col = 0;
		unsigned int categoria = 0;
		string frase(" ");

		string tipocorreo("") ;

		while (std::getline(lineStream, cell, ';')) {

			string buf;
			stringstream ss(cell);


			while (ss >> buf) {

				if (col == 0) {

					if (buf.compare("SPAM") == 0) {
						categoria = SPAM;
						tipocorreo = "SPAM";
						col++;
						continue;
					}

					if (buf.compare("NOSPAM") == 0) {
						categoria = NO_SPAM;
						tipocorreo = "NOSPAM";
						col++;
						continue;
					}

				}

				frase += " ";
				frase += buf;
				frase += " ";

				col++;
			}
		}

		double probSpam = probabilidadFrase(&frase, SPAM);
		double probNoSpam = probabilidadFrase(&frase, NO_SPAM);
	//	printf("frase tipo %s linea %i probabilidad spam %e  , probabilida NO spam %e \n",tipocorreo.c_str(),linea, probSpam, probNoSpam);


		if (probSpam > probNoSpam){
			double probSPAM = probSpam / probNoSpam;

//			if (categoria == SPAM){
//								catSPAMCorrectos++;
//							}else{
//								catSPAMIncorrectos++;
//							}


			if (probSPAM > 2){
				if (categoria == SPAM){
					catSPAMCorrectos++;
				}else{
					catSPAMIncorrectos++;
				}
			}else{
				if (categoria == SPAM){
					catSPAMIncorrectos++;
				}else{
					catSPAMCorrectos++;
				}
			}


		}else{

			if (categoria == SPAM){
				catNOSPAMIncorrectos++;
			}else{
				catNOSPAMcorrectos++;
			}

		}




		linea++;
	}
	printf("correos SPAM correctos %i , SPAM incorrectos %i , correos NO SPAM correctos %i , NO SPAM incorrectos %i\n", catSPAMCorrectos, catSPAMIncorrectos,catNOSPAMcorrectos, catNOSPAMIncorrectos);
}

void Bayes::printListadoSize() {

	HAL_TRACE_CORE(logger, " Size SPAM : %i", cantPalabras(SPAM));
	HAL_TRACE_CORE(logger, " Size NO_SPAM : %i", cantPalabras(NO_SPAM));

}

double Bayes::probabilidadSpam() {
	return PROB_SPAM;
}

double Bayes::probabilidadNoSpam() {
	return PROB_NO_SPAM;
}

double Bayes::probabilidadPalabra(string *word, unsigned int categoria, unsigned int npalabras) {

	unsigned int cantPalabra = getWordCant(word, categoria);

	unsigned int totalCategoria = cantPalabras(categoria);

	double cantPalabradouble = (double) cantPalabra;
	double totalCategoriadouble = (double) totalCategoria;
	double npalabrasdouble = (double) npalabras;

	double prob = (cantPalabradouble + 1) / (totalCategoriadouble + npalabrasdouble);

	return prob;
}

unsigned int Bayes::cantPalabras(unsigned int categoria) {
	map<unsigned int, map<string, unsigned int>*>::iterator iter = this->wordsmap->begin();

	iter = this->wordsmap->find(categoria);

	if (iter != this->wordsmap->end()) {

		map<string, unsigned int>* nodeword = iter->second;

		return nodeword->size();
	}

	//HAL_ERROR(logger, " Categoria no es SPAM =%i o NO SPAM= %i  -> %i", SPAM, NO_SPAM, categoria);
	return 0;
}

double Bayes::probabilidadFrase(string *frase, unsigned int categoria) {

	string bufcount;
	stringstream sscount(*frase);
	unsigned int numero_palabras = 0;

	while (sscount >> bufcount) {
		if (bufcount.size() > LARGO_MINIMO) {
			numero_palabras++;
		}
	}

	string buf;
	stringstream ss(*frase);

	double probaSpam = 1;
	double probaNoSpam = 1;

	while (ss >> buf) {

		std::transform(buf.begin(), buf.end(), buf.begin(), ::tolower);
		buf.erase(std::remove(buf.begin(), buf.end(), ' '), buf.end());

		if (buf.size() > LARGO_MINIMO) {

			std::wstring ws(buf.length(), L' ');

			std::copy(buf.begin(), buf.end(), std::back_inserter(ws));
			StemSpanish(ws);

			string* word = new string();
			word->assign(ws.begin(), ws.end());

			double probwordSpam = probabilidadPalabra(word, SPAM, numero_palabras);
			double probwordNoSpam = probabilidadPalabra(word, NO_SPAM, numero_palabras);

			probaSpam = probaSpam * probwordSpam;
			probaNoSpam = probaNoSpam * probwordNoSpam;

		}
	}
	double final = 1;
	if (categoria == SPAM) {

		final = (probabilidadSpam() * probaSpam) / (probaSpam + probaNoSpam * probabilidadNoSpam());
	}

	if (categoria == NO_SPAM) {

		final = (probabilidadNoSpam() * probaNoSpam) / (probaNoSpam + probaSpam * probabilidadSpam());

	}

	return final;

}

void Bayes::borrarPalabraCantMenor(unsigned int cant, unsigned int tipo) {

	if (cant != 0) {

		map<unsigned int, map<string, unsigned int>*>::iterator iter = this->wordsmap->begin();

		iter = this->wordsmap->find(tipo);

		if (iter != this->wordsmap->end()) {

			map<string, unsigned int>* nodeword = iter->second;

			if (nodeword != NULL) {

				map<string, unsigned int>::iterator it = nodeword->begin();

				for (it = nodeword->begin(); it != nodeword->end(); it++) {

					unsigned int cantidad = it->second;

					if (cantidad < cant) {
						nodeword->erase(it);
					}
				}

			} else {
				HAL_ERROR(logger, " Listado de palabras de la categoria es NULL...");

			}

		} else {
			HAL_ERROR(logger, " Categoria No encontrada ");

		}
	} else {
		HAL_ERROR(logger, " Palabra NULL ");

	}

}

void Bayes::borrarPalabraCantMayor(unsigned int cant, unsigned int tipo) {

	if (cant != 0) {

		map<unsigned int, map<string, unsigned int>*>::iterator iter = this->wordsmap->begin();

		iter = this->wordsmap->find(tipo);

		if (iter != this->wordsmap->end()) {

			map<string, unsigned int>* nodeword = iter->second;

			if (nodeword != NULL) {

				map<string, unsigned int>::iterator it = nodeword->begin();

				for (it = nodeword->begin(); it != nodeword->end(); it++) {

					unsigned int cantidad = it->second;

					if (cantidad > cant) {
						nodeword->erase(it);
					}
				}

			} else {
				HAL_ERROR(logger, " Listado de palabras de la categoria es NULL...");

			}

		} else {
			HAL_ERROR(logger, " Categoria No encontrada ");

		}
	} else {
		HAL_ERROR(logger, " Palabra NULL ");

	}

}

